home *** CD-ROM | disk | FTP | other *** search
- /*
- HE (great name, huh?)
-
- This is a simple little IFF picture viewer with support for
- pictures larger than the screen. So what? Well, it also handles
- HAM-E pictures. No big deal, since they're just hi-res pics, right?
- Well, sort-of. They are indeed IFF pictures, and can be shown
- with any picture viewer, but there is a problem. The HAM-E is
- triggered by the "magic cookie", which is contained in the first few
- lines of the picture. So, if you scroll the picture around, the
- magic cookie gets moved offscreen, and the HAM-E unlocks. Not cool.
- Enter this viewer. It can view just about any IFF picture you
- can throw at it. And if it detects a HAM-E picture, it will grab the
- cookie and keep it visible at all times while you scroll around.
- Pretty simple, really.
- If you're running under WorkBench 2.0x, the pictures will be
- displayed in overscan when necessary. This is so trivial to do under
- 2.0x that I figured I might as well. It's a lot more work under 1.3,
- so I didn't bother. You have to understand that this whole program
- was done on a "whim", and I only allowed it to take a couple of hours
- of my time...
- I have included the source just so that struggling programmers
- can use it as an example.
- Future features? I'd like to see color cycling support, and
- maybe anim support, but I just don't have the time. Later, maybe...
- As far as the legal issues go... Anyone who wants to use this
- code in a non-commercial product is free to do so. I do request a copy
- of such a product, though. Commercial uses are not permitted without
- contacting me first (I will almost certainly grant permission, I just
- want to know about things beforehand.) You may distribute this program
- as long as the source code is included, but may not make any profit
- from it other than the cost of the media it is on.
- HE works from the CLI only (sorry...) and is childishly simple
- to operate. Just say "HE [-n] <filename>". Once up and running, you
- click and drag the left mouse button to scroll around, and the right
- button to quit. Pretty simple, eh?
- The [-n] option will disable overscan under 2.0. For some reason,
- I have yet to be able to set my overscan preferences such that the
- HAM-E will lock on a severely overscanned image under 2.0. This
- provides a simple, if inelegant, way to get around that.
- I do not request any donation for the use of this program (other
- than for use of the source, as noted above). But if you want to
- contact me for any reason, send your comments, flames, and hard drives
- of outrageous capacity to:
-
- Robert Kesterson
- 6418 30th Street
- Lubbock, TX 79407
- (806)-792-3639
- BIX: rkesterson
- */
-
-
-
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <exec/types.h>
- #include <exec/ports.h>
- #include <exec/memory.h>
- #include <intuition/intuition.h>
- #include <intuition/screens.h>
- #include <graphics/gfxmacros.h>
- #include <graphics/gfx.h>
- #include <workbench/startup.h>
- #include "iff.h"
-
-
- BYTE REG_COOKIE[] = { 0xA2, 0xF5, 0x84, 0xDC, 0x6D, 0xB0, 0x7F, 0x14 };
- BYTE HAM_COOKIE[] = { 0xA2, 0xF5, 0x84, 0xDC, 0x6D, 0xB0, 0x7F, 0x18 };
-
-
- BOOL WB = FALSE; /* set this to true if run from workbench */
- /* then this silly macro will suppress printf()'s */
- #define wbprintf(x) if(!WB) printf(x)
-
- BOOL NO_OVERSCAN = FALSE;
- BOOL WB20x = FALSE; /* this is set true for WB 2.0x to allow overscan */
-
- char iffname[80]; /* iff filename */
-
- UWORD colortable[64]; /* save color map for later... */
- SHORT colorcount = 0; /* and the color count... */
-
- FILE *ifffile = NULL; /* This is the input picture */
-
- BitMapHeader header; /* This will hold the bitmap info... */
-
- struct Screen *screen = NULL; /* The screen for the picture */
- struct Window *window = NULL; /* and the window to hold it */
- struct BitMap *sbmap = NULL; /* and the actual bitmap */
- struct Window *cookie = NULL; /* this will hold the cookie, if any */
- struct RastPort *rport;
-
-
- struct GfxBase *GfxBase = NULL; /* library stuff */
- struct IntuitionBase *IntuitionBase = NULL;
- struct LayersBase *LayersBase = NULL;
-
- BOOL OpenStuff(void); /* some prototypes */
- BOOL OpenLibs(void);
- void CheckForCookies(void);
- void SetOverScan(struct NewScreen *ns,BitMapHeader *bmhd);
- void ShowIt(void);
- void CloseStuff(void);
- struct BitMap *create_bitmap(UWORD width, UWORD height, UBYTE depth);
- void close_bitmap(struct BitMap *bitmap);
-
-
- /*
- Here's the main function. Doesn't seem to do a whole lot, does it?
- */
-
- void main(argc,argv)
- int argc;
- char **argv;
- {
- BOOL trouble = FALSE;
-
- if((argc==1) || (argv[1][0] == '?'))
- {
- printf("\n%s -- by Robert Kesterson",argv[0]);
- printf("\nThis YAIFFV (Yet Another IFF Viewer) allows scrolling");
- printf("\naround in oversize pictures, including HAM-E pictures.");
- printf("\nUsage is: %s iff_file.\n",argv[0]);
- exit(10);
- }
- if(argv[1][0] == '-')
- {
- strcpy(iffname,argv[2]);
- NO_OVERSCAN = TRUE;
- }
- else
- strcpy(iffname,argv[1]);
- trouble = OpenStuff();
- if(!trouble)
- ShowIt();
- CloseStuff();
- }
-
- /*
- OpenStuff() opens everything up and sets up the screen and such.
- It figures out what the bitmap needs are and allocates one.
- Then it sets the colormap for the screen and reads the picture into
- the SuperBitMap. Then it does some Layers fiddling to refresh the
- initial window, and returns to the caller.
- */
-
- BOOL OpenStuff()
- {
- struct NewScreen newscreen;
- struct NewWindow newwindow =
- {
- 0,0,0,0, /* left, top, width, height (fill in below) */
- -1,-1, /* use default pens */
- MOUSEMOVE|MOUSEBUTTONS, /* IDCMP flags */
- BACKDROP|RMBTRAP|SUPER_BITMAP|BORDERLESS|ACTIVATE|GIMMEZEROZERO|REPORTMOUSE,
- NULL, /* no gadgets */
- NULL, /* no checkmark */
- NULL, /* no title */
- NULL, /* screen -- fill in below */
- NULL, /* not superbitmap ...yet... */
- 0,0,0,0, /* max and min sizes */
- CUSTOMSCREEN
- };
- BOOL error;
- SHORT count,tempheight=0, tempwidth=0;
- BYTE hires=1, lace=1;
-
- for(count=0;count<64;count++)
- colortable[count] = 0x0000; /* initialize color table */
- error = OpenLibs();
- if(error)
- return TRUE;
- if((ifffile = fopen(iffname,"rb")) == NULL)
- { /* hey dude, get the name right... */
- wbprintf("\nCan't open IFF file!!\n");
- return TRUE;
- } /* Open the IFF file and set up the screen */
- error = GetBMHD(ifffile,&header);
- if(error)
- {
- wbprintf("\nFile error or invalid IFF file.\n");
- return TRUE;
- }
- newscreen.LeftEdge = header.x; /* figure out what the screen */
- newscreen.TopEdge = header.y; /* needs to look like */
- newscreen.ViewModes = 0;
- newscreen.Type = CUSTOMSCREEN | SCREENBEHIND | SCREENQUIET;
- newscreen.Height = header.h;
- newscreen.Width = header.w;
- if(header.h < header.pageHeight) /* is it a brush? */
- newscreen.Height = (header.pageHeight > 240) ? 400 : 200;
- else if(header.h > header.pageHeight)
- newscreen.Height = header.pageHeight; /* or a superbitmap? */
- if(header.w < header.pageWidth)
- newscreen.Width = (header.pageWidth > 384) ? 640 : 320;
- else if(header.w > header.pageWidth)
- newscreen.Width = header.pageWidth;
- newscreen.Depth = header.nplanes;
- newscreen.DetailPen = 0;
- newscreen.BlockPen = 1;
- newscreen.DefaultTitle = NULL;
- newscreen.Gadgets = NULL;
- newscreen.Font = NULL; /* probably should declare one... */
- newscreen.CustomBitMap = NULL;
- error = GetViewModes(&newscreen, ifffile);
- if(error)
- {
- wbprintf("\nProblem with viewmodes!\n");
- return TRUE;
- }
- if((newscreen.Width > 384) && (newscreen.Depth <= 4) && !(newscreen.ViewModes & HAM))
- {
- newscreen.ViewModes |= HIRES;
- hires = 2;
- }
- if(newscreen.Height > 200)
- {
- newscreen.ViewModes |= LACE;
- lace = 2;
- }
- SetOverScan(&newscreen,&header);
- if((newscreen.Width > 384) && (newscreen.Depth <= 4) && !(newscreen.ViewModes & HAM))
- newscreen.ViewModes |= HIRES;
- if(newscreen.Height > 200) /* these might need to be */
- newscreen.ViewModes |= LACE; /* changed, so just make sure */
- if(newscreen.Width<320)
- {
- tempwidth = newscreen.Width;
- newscreen.Width = 320;
- }
- if(newscreen.Height<200*lace)
- {
- tempheight = newscreen.Height;
- newscreen.Height = 200*lace;
- }
- screen = (struct Screen *)OpenScreen(&newscreen);
- if(!screen)
- { /* low on RAM, maybe? */
- wbprintf("\nCan't open the screen!\n");
- return TRUE;
- }
- if((tempwidth) && (tempwidth < newscreen.Width))
- newwindow.Width = tempwidth;
- else
- newwindow.Width = newscreen.Width;
- if((tempheight) && (tempheight < newscreen.Height))
- newwindow.Height = tempheight;
- else
- newwindow.Height = newscreen.Height; /* make a screen-sized window */
- newwindow.Screen = screen;
- sbmap = create_bitmap(header.w,header.h,header.nplanes);
- if(!sbmap)
- {
- wbprintf("\nNo Memory for SuperBitMap!!\n");
- return TRUE;
- }
- newwindow.BitMap = sbmap; /* jam bitmap into the window */
- window = (struct Window *)OpenWindow(&newwindow);
- if(!window)
- {
- wbprintf("\nCan't open a window!!\n");
- return TRUE;
- }
- rport = window->RPort; /* need this later */
- colorcount = GetColorMap(ifffile,colortable); /* fix the colors */
- LoadRGB4(&screen->ViewPort,colortable,colorcount);
- error = ReadPic(sbmap,ifffile,&header); /* read the image */
- if(error)
- {
- wbprintf("\nError decoding IFF file!\n");
- return TRUE;
- }
- LockLayerRom(window->WLayer); /* refresh the window */
- CopySBitMap(window->WLayer); /* (only do it this way the */
- UnlockLayerRom(window->WLayer); /* first time.) */
- CheckForCookies(); /* HAM-E, by any chance? */
- ShowTitle(screen,FALSE);
- ScreenToFront(screen);
- return FALSE;
- }
-
-
- /*
- OpenLibs() just opens the libraries we'll need and sets the WB20x
- flag if we're running under 2.0x.
- */
-
- BOOL OpenLibs(void)
- {
- IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",36);
- if(IntuitionBase)
- WB20x = TRUE;
- else
- IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0);
- GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0);
- LayersBase = (struct Library *)OpenLibrary("layers.library",0);
- if((!IntuitionBase) || (!GfxBase) || (!LayersBase))
- return TRUE; /* Like maybe you yanked your ROMs out? */
- else
- return FALSE;
- }
-
-
- /*
- SetOverScan() just tries to intelligently set up overscan images
- under workbench 2.0x. Pretty trivial, actually.
- */
-
- void SetOverScan(newscreen,header)
- struct NewScreen *newscreen;
- BitMapHeader *header;
- {
- SHORT hires = 1, lace = 1;
-
- if((newscreen->Width > 384) && (newscreen->Depth <= 4) && !(newscreen->ViewModes & HAM))
- {
- newscreen->ViewModes |= HIRES;
- hires = 2;
- }
- if(newscreen->Height > 200)
- {
- newscreen->ViewModes |= LACE;
- lace = 2;
- }
- if((!WB20x) || NO_OVERSCAN) /* don't mess with overscan under 1.3 */
- {
- if(newscreen->Height > (200 * lace))
- newscreen->Height = 200 * lace;
- if(newscreen->Width > (320 * hires))
- newscreen->Width = 320 * hires;
- return;
- }
- if(header->h > 220 * lace)
- {
- newscreen->Height = 240 * lace; /* center if overscan */
- newscreen->TopEdge -= (newscreen->Height - (200 * lace)) / 2;
- }
- else if(header->h > 200 * lace)
- {
- newscreen->Height = 220 * lace;
- newscreen->TopEdge -= (newscreen->Height - (200 * lace)) / 2;
- }
- if(header->w > 352 * hires) /* severe overscan? */
- {
- newscreen->Width = 384 * hires; /* center it */
- newscreen->LeftEdge -= (newscreen->Width - (320 * hires)) / 2;
- }
- else if(header->w > 320 * hires) /* normal overscan? */
- {
- newscreen->Width = 352 * hires; /* center it */
- newscreen->LeftEdge -= (newscreen->Width - (320 * hires)) / 2;
- }
- return;
- }
-
- /*
- CloseStuff() attempts to figure out all the garbage I didn't already
- close somewhere and clean up after me. Important when closing things
- elsewhere to set them to NULL so they don't get re-closed here. Good
- way to get a lesson in meditation....
- */
-
- void CloseStuff()
- {
- if(ifffile)
- fclose(ifffile);
- if(cookie)
- CloseWindow(cookie);
- if(window)
- CloseWindow(window);
- if(screen)
- CloseScreen(screen);
- if(sbmap)
- close_bitmap(sbmap);
- if(LayersBase)
- CloseLibrary(LayersBase);
- if(GfxBase)
- CloseLibrary(GfxBase);
- if(IntuitionBase)
- CloseLibrary(IntuitionBase);
- }
-
-
- /*
- CheckForCookies() checks the main window's bitmap for HAM-E cookies,
- assuming that they will exist only in the upper left corner of the
- image (although I suppose you could put them on any scanline...).
- If any are present, we set up a window _just_ big enough to hold the
- cookie lines and copy the cookie into it. Then when you scroll the
- main window around, the little cookie window will keep the HAM-E
- locked in. Simple, eh?
- */
-
- void CheckForCookies()
- {
- struct NewWindow newwindow =
- {
- 0,0,0,0, /* left, top, width, height (fill in below) */
- -1,-1, /* use default pens */
- NULL, /* IDCMP flags (none for this window) */
- BORDERLESS|GIMMEZEROZERO,
- NULL, /* no gadgets */
- NULL, /* no checkmark */
- NULL, /* no title */
- NULL, /* screen -- fill in below */
- NULL, /* not superbitmap */
- 0,0,0,0, /* max and min sizes */
- CUSTOMSCREEN
- };
- SHORT line,byte;
- BYTE cookielines[8][8]; /* 8 lines of 8 BYTEs each for cookies */
-
- for(line=0;line<8;line++)
- for(byte=0;byte<8;byte++)
- {
- cookielines[line][byte] = (BYTE)(ReadPixel(window->RPort,byte*2,line) << 4);
- cookielines[line][byte] |= (BYTE)ReadPixel(window->RPort,byte*2+1,line);
- }
- for(line=0;line<8;line++)
- {
- for(byte=0;byte<8;byte++)
- {
- if(cookielines[line][byte] == REG_COOKIE[byte])
- continue;
- else if(cookielines[line][byte] != HAM_COOKIE[byte])
- break;
- }
- if(cookielines[line][byte] == REG_COOKIE[byte])
- continue; /* check to see if we broke from the first loop */
- else if(cookielines[line][byte] != HAM_COOKIE[byte])
- break;
- }
- if((line==0) && (byte<8)) /* no cookies here... */
- return;
- if(line>=0)
- {
- newwindow.LeftEdge = window->LeftEdge;
- newwindow.TopEdge = window->TopEdge;
- newwindow.Height = line+1; /* got to be at least one... */
- newwindow.Width = 640; /* all we'd need for now, right? */
- newwindow.Screen = screen; /* got to put it on a screen... */
- cookie = (struct Window *)OpenWindow(&newwindow);
- if(!cookie)
- {
- wbprintf("Can't open Cookie window!\n");
- return;
- }
- BltBitMap(sbmap,0,0,cookie->RPort->BitMap,0,0,
- cookie->Width,cookie->Height,0x0C0,0x0FF);
- }
- return;
- }
-
-
- /*
- pointer data (see GetClip(), below).
- */
-
- UWORD chip hand_data[] =
- {
- 0x0000,0x0000, /* control words */
- 0x0000,0x0340, /* data words */
- 0x0340,0x0CB0,
- 0x0550,0x0AA8,
- 0x0558,0x0AA4,
- 0x02A8,0x0554,
- 0x02F8,0x6504,
- 0x61F8,0x9204,
- 0x73F8,0x8C04,
- 0x3FF8,0x4004,
- 0x1FF8,0x2004,
- 0x1FF0,0x2008,
- 0x07F0,0x1808,
- 0x01E0,0x0610,
- 0x00E0,0x0110,
- 0x00C0,0x0100,
- 0x0000,0x0000 /* more control words */
- };
-
-
-
- void ShowIt()
- {
- struct IntuiMessage *msg = NULL;
- struct IntuiMessage tempmsg;
- BOOL mousedown = FALSE; /* TRUE if left mouse down */
- BOOL message_ready = FALSE; /* TRUE if tempmsg has a valid message */
- SHORT x,y;
- SHORT dx,dy;
- SHORT oldx,oldy;
- /* clear the port first thing */
- while(msg = (struct IntuiMessage *)GetMsg(window->UserPort))
- ReplyMsg(msg);
- oldx = oldy = x = y = 0;
- do
- {
- oldx = x;
- oldy = y;
- if(!message_ready)
- {
- WaitPort(window->UserPort); /* call me sometime */
- msg = (struct IntuiMessage *)GetMsg(window->UserPort);
- memcpy(&tempmsg,msg,(unsigned int)sizeof(struct IntuiMessage));
- ReplyMsg(msg); /* send it back */
- }
- else
- message_ready = FALSE; /* fixin' to use tempmsg */
- x = tempmsg.MouseX; /* where's the mouse? */
- y = tempmsg.MouseY;
- if(tempmsg.Class == MOUSEMOVE) /* got a mouse in motion */
- {
- if(mousedown) /* got a button down */
- {
- while(msg = (struct IntuiMessage *)GetMsg(window->UserPort))
- { /* look ahead while moving */
- if(msg->Class == MOUSEMOVE)
- {
- x = msg->MouseX;
- y = msg->MouseY;
- ReplyMsg(msg);
- continue;
- }
- else /* not moving anymore */
- {
- memcpy(&tempmsg,msg,(unsigned int)sizeof(struct IntuiMessage));
- ReplyMsg(msg);
- message_ready = TRUE;
- break;
- }
- }
- }
- if(mousedown) /* scrolling, are we? */
- {
- dx = (oldx - x); /* get offsets */
- dy = (oldy - y);
- /* bounds checks */ if(window->WLayer->Scroll_X + dx <0)
- dx = window->WLayer->Scroll_X;
- if(window->WLayer->Scroll_Y + dy <0)
- dy = window->WLayer->Scroll_Y;
- if(window->WLayer->Scroll_X +dx > (window->WLayer->SuperBitMap->BytesPerRow * 8-window->Width))
- dx = window->WLayer->SuperBitMap->BytesPerRow * 8-window->Width-window->WLayer->Scroll_X;
- if(window->WLayer->Scroll_Y + dy > window->WLayer->SuperBitMap->Rows-window->Height)
- dy = window->WLayer->SuperBitMap->Rows-window->Height-window->WLayer->Scroll_Y;
- if(window->WLayer->SuperBitMap->BytesPerRow*8 <= window->Width)
- dx = 0;
- if(window->WLayer->SuperBitMap->Rows <= window->Height)
- dy = 0;
- if(dx%2) /* limit to two-pixel move increments */
- dx--;
- /* Scroll BitMap */ ScrollLayer(window->WLayer->LayerInfo,window->WLayer,dx,dy);
- continue;
- }
- }
- if(tempmsg.Class == MOUSEBUTTONS)
- {
- if((mousedown) && (tempmsg.Code == SELECTUP))
- {
- mousedown = FALSE;
- ClearPointer(window);
- }
- if(!mousedown)
- {
- if(tempmsg.Code == SELECTDOWN)
- {
- mousedown = TRUE;
- SetPointer(window,&hand_data,15,14,0,0);
- }
- }
- if(tempmsg.Code == MENUUP)
- break;
- }
- }
- while(TRUE);
- }
-
- /*
- Create_bitmap() is a pretty generic routine to allocate and initialize
- a bitmap.
- */
-
- struct BitMap *create_bitmap(width,height,depth)
- UWORD width,height;
- UBYTE depth;
- {
- short i, error_flag = (SHORT)FALSE;
- struct BitMap *pbitmap = NULL;
- unsigned char *planepointer;
-
- if((depth>0L) && (width>0L) && (height>0L))
- {
- pbitmap = (struct BitMap *)AllocMem(sizeof(struct BitMap),
- MEMF_CHIP | MEMF_CLEAR);
- if(pbitmap != NULL)
- {
- InitBitMap(pbitmap,depth,width,height);
- for(i=0;i<depth;i++)
- {
- planepointer = (PLANEPTR)AllocMem(RASSIZE(width,height),MEMF_CHIP|MEMF_CLEAR);
- if(planepointer)
- pbitmap->Planes[i] = planepointer;
- else
- error_flag = TRUE;
- }
- }
- }
- if(error_flag == TRUE)
- {
- close_bitmap(pbitmap);
- pbitmap = NULL;
- }
- return(pbitmap);
- }
-
- /*
- close_bitmap() just frees up all the memory in a BitMap that was
- previously allocated with create_bitmap().
- */
-
- void close_bitmap(pbitmap)
- struct BitMap *pbitmap;
- {
- unsigned char *planepointer;
- unsigned long depth,width,height;
- short i;
-
- if(pbitmap != NULL)
- {
- depth = pbitmap->Depth;
- width = pbitmap->BytesPerRow * 8;
- height = pbitmap->Rows;
- for ( i=0; i<depth; i++)
- {
- planepointer = pbitmap->Planes[i];
- if(planepointer != NULL)
- FreeMem(planepointer,RASSIZE(width,height));
- }
- FreeMem(pbitmap,sizeof(struct BitMap));
- }
- }
-
-